#!/usr/bin/python3
#
# Copyright (c) 2020, 2023  NVI, Inc.
#
# This file is part of VLBI Field System
# (see http://github.com/nvi-inc/fs).
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
"""application that starts a thread that receives the output from 'tail -f'. """

from tkinter import *
import sys
import time
import threading
import os
import subprocess


class MainGui:
    """MainGui makes graphic stuf...
    """
    filename = ''
    pid = 0

    def __init__(self, title = 'Logreader'):


        global master
        #make Tk object:
        master = Tk()

        #make tools, make it global so object has the same reference to all classes
        global tools
        tools = Tools()
        master.title(title)

        master.protocol('WM_DELETE_WINDOW', lambda:tools.exitProg())

        #menubar:
        menubar = Menu(master)
        filemenu = Menu(menubar, tearoff = 0)
        filemenu.add_command(label="Open", command=tools.openLog)
        filemenu.add_command(label="Quit", command=tools.exitProg)
        menubar.add_cascade(label="File", menu = filemenu)

        runmenu = Menu(menubar, tearoff = 0)
        runmenu.add_command(label='Read file', command = tools.startUp)
        runmenu.add_command(label='Stop reading', command = tools.stop)
        runmenu.add_command(label='Clear', command = tools.clearTable)
        runmenu.add_command(label='Find log file', command = tools.findFile)
        menubar.add_cascade(label = "Tools", menu =runmenu)

        master.config(menu=menubar)

        #master frame:
        frame = Frame(master)
        frame.pack()

        w = []
        global label
        label=[None]*15
        _label=[None]*3
        #create labels
        for i in range(15):
            label[i]=_label[:]

        #Create a UNIQUE! stringVar at every index/subindex
        for i in range(15):
            for j in range(3):
                label[i][j] = StringVar()

        #setting header labels
        k=0
        for i in ['Amplitude', 'Phase', 'Time']:
            label[0][k].set(i)
            k+=1
        #create table
        for i in range(15):
            w.append(Frame(frame, borderwidth = 0))
            w[i].pack(side = TOP, fill = X)
            Label(w[i], text = i, width = 3, pady=0, bd=0).pack(side=LEFT)
            Label(w[i], textvariable = label[i][0], width = 10, pady=0, bd=0).pack(side=LEFT)
            Label(w[i], textvariable = label[i][1], width = 6, pady=0, bd=0).pack(side=LEFT)
            Label(w[i], textvariable = label[i][2], pady=0, bd=0, width = 9).pack(side=LEFT)



        statusbar = Frame(master)
        statusbar.pack(side = BOTTOM, fill = X)
        Label(statusbar, textvariable = tools.status, relief = SUNKEN).pack(fill = X)
        tools.findFile()
        master.mainloop()



class Tools:
    def __init__(self):
        self.status = StringVar()
        self.status.set('idle')
    def startUp(self):
        #initiate thread if file chosen
        if MainGui.filename:
            self.status.set('log name: '+os.path.splitext(os.path.basename(MainGui.filename))[0])
            t1 = FileReader()
            t1.setDaemon(1) #Makes thread Daemonic, i.e sys.exit w.o errors possible
            t1.start()
        else:
            self.message('Pick a log file')

    def message(self, text):
        win = Toplevel()
        Label(win, text=text).pack()
        Button(win, text='OK', command = win.destroy).pack()

    def qmessage(self, label, text):
        import tkinter.messagebox
        x = tkinter.messagebox.askokcancel(label,text)
        # x=1 : ok, x=0 : Cancel
        return x


    def exitFileReader(self):
        #kills the thread of the FileReader if there is one
        if(MainGui.pid):
            os.popen('kill ' + str(MainGui.pid))
            #reset pid
            MainGui.pid = 0

    def exitProg(self):

        self.exitFileReader()
        master.destroy()
        sys.exit()

    def openLog(self):
        import tkinter.filedialog
        MainGui.filename = tkinter.filedialog.askopenfilename()


    def findFile(self):
        lf = LogFinder()
        lf.setDaemon(1)
        lf.start()

    def stop(self):
        #stops FileReader from reading, sets status to idle and clears the table
        self.exitFileReader()
        self.clearTable()
        self.status.set('idle')


    def clearTable(self):
        for i in range(1,15):
            for j in range(3):
                label[i][j].set('')


class FileReader(threading.Thread):
    def run(self):
        lr = LineReader()
        #try to open file, on fail, display error
        try:
            child = subprocess.Popen(['tail', '-f', MainGui.filename],stdout=subprocess.PIPE,stderr=None,text=True,close_fds=True)
        except:
            tools.stop()
            tools.message("Failed to run tail!")
        else:
            output=child.stdout
            MainGui.pid = child.pid
        # child.poll() returns the exit status of child... None for running
            while child.poll() == None :
                position = -1
                line = output.readline()
                l1 = lr.getData(line)
                if l1: #if we got a list back, else None => l1 => false
                    label[l1[0]][0].set(l1[2][0]) #amplitude
                    label[l1[0]][1].set(l1[2][1]) #phase
                    label[l1[0]][2].set(l1[3]) #date of measurement





class LogFinder(threading.Thread):
    def run(self):
        while 1:
            try:
                 _child = subprocess.Popen('lognm',stdout=subprocess.PIPE,stderr=None,text=True,close_fds=True)
            except:
                tools.message('Could not run lognm')
                break
            else:
                logfile = _child.stdout
                _filename = logfile.read().rstrip()
                logfile.close()
                filename = "%s%s%s" % ('/usr2/log/',_filename,'.log')
                if _filename=='': #no log, quit, remove """ to get question
                    """
                    _answer = tools.qmessage("No log file found", "Quit?")
                    if _answer:
                            tools.exitProg()
                    else:
                            tools.exitFileReader()
                            tools.status.set('idle')
                            #if cancel, stop thread:
                            break
                    """
                    tools.exitProg()
                elif not filename==MainGui.filename: #change of logfile!
                    #give MainGui the new filename
                    MainGui.filename = filename
                    #kill the Filereader thread if there is one:
                    tools.exitFileReader()
                    #start new thread with new filename
                    tools.startUp()
                #re-check every 10s
                time.sleep(1)

class LineReader:

#constructor receives the line that is to be analyzed.

    def __init__(self):
        #usbxy channels
        self.xchannel = 0
        self.ychannel = 0
        self.initiate = 1
        self.firstday = 0

    def getData(self, line):
        identification_table = ['usbx', 'usby', '/pcalports=', '/vsi4=,']
        for match in identification_table:
            listpos = 0
            position = line.find(match)
            if (position !=-1):
                position += len(match)
                if (match == '/pcalports=') or (match =='/vsi4=,'):
                    _nfind = line[position:-1].split(',')
                    xchannel = _nfind[0]
                    ychannel = _nfind[1]
                    self.setChannel([xchannel, ychannel])
                #check if xy channels are set
                elif (self.xchannel and self.ychannel):
                    data = 'something new'
                    #check if xy channels are set
                    if (match == 'usbx'):
                        listpos = self.xchannel
                        #record amp and phase
                        _d1 = line[position+1:-1].split(' ')
                        if len(_d1)<4:
                            _d1 = ['*']*4
                        data = [_d1[2], _d1[3]]
                    if (match == 'usby'):
                        listpos = self.ychannel
                        #record amp and phase
                        _d1 = line[position+1:-1].split(' ')
                        if len(_d1)<4:
                            _d1 = ['*']*4
                        data = [_d1[2], _d1[3]]
                    date = self.fixDate(line[0:20])
                    return [int(listpos), match, data,date]
                    #return listpos


    def setChannel(self, channel):
        self.xchannel = channel[0]
        self.ychannel = channel[1]


    def fixDate(self,date):
        _date = date[9:-3]
        return _date



if __name__ == "__main__":
    startProg = MainGui()
